/*
 * Bus.cpp
 *
 */
#include <sstream>
#include "Bus.h"
#include "API/SalaBus.h"
#include "logger/logger.h"

namespace API {

Bus::Bus(BusId nBus):
		m_busSem(new BusSemaphore("/tmp/bus_sem")),
		m_sala(new SalaBus(API::SalaBus::ATENDER_BUS)),
		m_doRun(true),
		m_capacidad(50),
		m_loadPassengerQueue("/tmp/bus_load_queue"),
		m_unloadPassengerQueue("/tmp/bus_unload_queue"),
		m_busId(nBus)
{
}

Bus::~Bus()
{
	delete m_sala;
	delete m_busSem;
}

void Bus::suboAlBus(Persona &persona, int &error)
{
	entryBusRequest req;
	std::stringstream ss;

	ss << "Persona "<< persona.m_id<<" subiendo al bus:"<<m_busId;

	CLogger::log(ss.str(),LogLevelEnum::INFO);

	//TODO convert
	req.m_persona.m_id = persona.m_id;
	m_loadPassengerQueue.put(m_busId,req);

	m_unloadPassengerQueue.get(persona.m_id);

}

void Bus::bajoDelBus(Persona &persona, int &error)
{

}

void Bus::init()
{
	m_loadPassengerQueue.destroy();
	m_unloadPassengerQueue.destroy();
	m_busSem->init();
}

void Bus::destroy()
{
	m_loadPassengerQueue.destroy();
	m_unloadPassengerQueue.destroy();
	m_busSem->destroy();
}

void Bus::indicarHayPasajeros()
{
	m_busSem->signal(m_busId);
}

void Bus::run( SalaId sala1,SalaId sala2)
{
	std::stringstream ss;
	Persona persona;
	int error;

	//Asigno originalmente las salas
	m_salaActual = sala1;
	m_salaDestino = sala2;

	while(m_doRun)
	{
		descargar();

		if(m_pasajeros.size() == m_capacidad)
		{
			viajar();
			continue;
		}

		if(m_sala->tienePasajeros(m_salaActual))
		{
			ss.str("");
			ss << "Bus getting passenger from sala:"<< m_salaActual;
			CLogger::log(ss.str(),LogLevelEnum::INFO);

			m_busSem->wait(m_busId);

			persona = m_sala->getPasajero(m_salaActual);

			ss.str("");
			ss << "Persona "<< persona.m_id<<" lista para subir al bus.";

			CLogger::log(ss.str(),LogLevelEnum::INFO);

			m_sala->indicarBusDestino(m_busId,persona);

			m_loadPassengerQueue.get(m_busId);
			m_pasajeros.push_back(persona);

			ss.str("");
			ss << "Persona "<< persona.m_id<<" subio al bus.";

			continue;
		}

		if(m_pasajeros.size() != 0)
		{
			viajar();
			continue;
		}

		if(m_sala->tienePasajeros(m_salaDestino))
		{
			viajar();
			continue;
		}

		m_busSem->wait(m_busId);
		m_busSem->signal(m_busId);
	}
}

void Bus::viajar()
{
	std::stringstream ss;
	SalaId temp;

	temp = m_salaActual;
	m_salaActual = m_salaDestino;
	m_salaDestino = temp;

	//TODO poner un sleep

	ss << "Bus "<< m_busId<<" viajando";
	CLogger::log(ss.str(),LogLevelEnum::INFO);

}

void Bus::descargar()
{
	personaList::iterator it;
	std::stringstream ss;

	for(it = m_pasajeros.begin();it != m_pasajeros.end(); it++ )
	{
		entryBusReply req;
		//TODO ver la copia
		req.m_persona.m_id = it->m_id;

		ss << "Bus "<< m_busId<<" avisa a pasajero "<< it->m_id<< " que tiene que bajar";
		CLogger::log(ss.str(),LogLevelEnum::INFO);

		m_unloadPassengerQueue.put(it->m_id,req);
	}

	m_pasajeros.clear();
}

}
